/*
 * @author: Brandon Wong
 */

package com.apps.services;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

import com.apps.datastore.dao.CourseInformationObject;
import com.apps.datastore.dao.SectionInformationObject;
import com.apps.ubc.cc.model.BuildingModel;
import com.apps.ubc.cc.model.GoogleDirectionModel;
import com.apps.ubc.cc.model.LatLongModel;

public class CourseSummaryService {

	private final static String[] days = { "Mon", "Tue", "Wed", "Thu", "Fri" };
	private final static String[] term = { "1", "2" };

	/*
	 * Prints out the summary schedule of the terms and days.
	 */
	public String getSummarySchedule(List<SectionInformationObject> course) {

		String summary = "";
		List<SectionInformationObject> sort_term;

		for (int j = 0; j < term.length; j++) {
			summary = summary.concat("Term " + term[j] + ":\n");
			sort_term = sortTerm(course, term[j]);
			for (int i = 0; i < days.length; i++) {
				summary = summary.concat(sortDayBreak(sort_term, days[i]));
			}
			summary = summary.concat("\n");
		}
		sort_term = null;
		return summary;
	}

	public List<LatLongModel> findUnique(
			List<LatLongModel> list) {
		List<LatLongModel> result = new ArrayList<LatLongModel>();
		for(Iterator<LatLongModel> i = list.iterator(); i.hasNext();){
			LatLongModel llm = i.next();
			if(!result.contains(llm))
				result.add(llm);
			
		}
		
		return result;

	}

	// Takes in a unsorted list of SIO and returns the lat/long of the SIO
	// specified by term. Sorted by day and then by time.
	public List<LatLongModel> getLatLongByTerm(
			List<SectionInformationObject> course_list, String term) {

		if (course_list == null || term == null) {
			return null;
		} else if (course_list.size() == 0) {
			return null;
		} else if (!(term.equals("1") || term.equals("2"))) {
			return null;
		}
		// list to store sorted term
		List<SectionInformationObject> sorted_term = new LinkedList<SectionInformationObject>();
		// List to store sorted Day
		List<SectionInformationObject> sorted_day = null;
		// Return type
		List<LatLongModel> latLong = new LinkedList<LatLongModel>();
		List<LatLongModel> buffer;

		for (int i = 0; i < course_list.size(); i++) {
			// Sort by term.
			if (course_list.get(i).getTerm().equals(term)) {
				sorted_term.add(course_list.get(i));

			}
		}

		// Now it's sorted by term. Remove duplicate
		// sorted_term=findUnique(sorted_term);

		for (int j = 0; j < days.length; j++) {
			// Now, sort by day.
			sorted_day = sortByDay(sorted_term, days[j]);
			// Lastly, sort by time
			sorted_day = sort(sorted_day);
			buffer = getLatLongInDay(sorted_day);
			if (buffer.size() != 0) {
				latLong.addAll(buffer);
			}

		}
		
		List<LatLongModel> llml = findUnique(latLong);
		// Now it's sorted by term and time.
		return llml;
	}

	// Gets the lat/long of a sorted List of a day.
	private List<LatLongModel> getLatLongInDay(
			List<SectionInformationObject> course_list) {

		List<LatLongModel> sort_term = new LinkedList<LatLongModel>();

		if (course_list.size() == 0) {
			return sort_term;
		}

		for (int j = 0; j < course_list.size(); j++) {

			// This is to get the lat/long
			UBCWayfindingService addrParser;
			BuildingModel addr;

			addrParser = new UBCWayfindingService();
			addr = addrParser.search(course_list.get(j).getBuilding());

			if (addr != null) {
				LatLongModel geo = new LatLongModel(addr.getLatitude(),
						addr.getLongitude());
				sort_term.add(geo);
				System.out.println("Course name: "
						+ course_list.get(j).getSectionId());
			}

		}

		return sort_term;
	}

	/*
	 * Finds the break within classes in a day.
	 */
	private String findBreakinDay(List<SectionInformationObject> day,
			String today) {

		double total_distance = 0;
		int total_time = 0;
		// First sort it...
		day = sort(day);
		String breaktime = today + ":\n";
		GoogleDirectionsService service = new GoogleDirectionsService();

		// Now we form the summary statement.
		if (day.size() == 0) {
			breaktime = breaktime.concat("No class.\n");
		} else if (day.size() == 1) {
			breaktime = breaktime.concat("There's only one lesson today.\n");
		}

		for (int i = 0; i < day.size() - 1; i++) {

			if (i == 0) {
				breaktime = breaktime.concat("Your lecture starts at "
						+ day.get(i).getStart() + "\n");
			}
			SectionInformationObject class_1 = day.get(i);
			SectionInformationObject class_2 = day.get(i + 1);
			GoogleDirectionModel model = service
					.getDirections(class_1, class_2);
			total_distance += model.getDistance();
			total_time += model.getTime();
			if (!class_1.getEnd().equals(class_2.getStart())) {
				breaktime = breaktime.concat("Break from: ");
				breaktime = breaktime.concat(class_1.getEnd());
				breaktime = breaktime.concat("-");
				breaktime = breaktime.concat(class_2.getStart());
				breaktime = breaktime.concat("\n");
			}

			if (i == day.size() - 1) {
				breaktime = breaktime.concat("Your lecture ends at "
						+ day.get(i).getStart() + "\n");
			}

		}
		// Now that the summary of classes are printed. Print the total
		// walking time.
		breaktime = breaktime.concat("Total walking distance is "
				+ total_distance + "m\n");
		breaktime = breaktime.concat("Total time is " + total_time + "m\n");
		return breaktime;
	}

	/*
	 * Sort the given list by it's start time
	 */
	public List<SectionInformationObject> sort(
			List<SectionInformationObject> to_sort) {

		List<SectionInformationObject> sorted = new LinkedList<SectionInformationObject>();
		boolean changed;

		for (int i = 0; i < to_sort.size(); i++) {
			changed = false;
			for (int j = 0; j < sorted.size(); j++) {

				// Parse the time first.
				String[] time_1 = to_sort.get(i).getStart().split(":");
				String[] time_2 = sorted.get(j).getStart().split(":");
				int hour_1 = Integer.parseInt(time_1[0]);
				int hour_2 = Integer.parseInt(time_2[0]);

				if (hour_1 < hour_2) {

					if (j == 0) {
						// The first element
						sorted.add(0, to_sort.get(i));
						changed = true;

					} else {
						sorted.add(j, to_sort.get(i));
						changed = true;

					}

					break;
				} else if (hour_1 == hour_2) {
					int min_1 = Integer.parseInt(time_1[1]);
					int min_2 = Integer.parseInt(time_2[1]);

					if (min_1 > min_2) {
						if (j == 0) {
							// THe first element
							sorted.add(0, to_sort.get(i));
							changed = true;

						} else {
							sorted.add(j, to_sort.get(i));
							changed = true;

						}
					}
					break;
				}
			}
			if (changed == false) {
				sorted.add(to_sort.get(i));
			}
		}
		return sorted;
	}

	/*
	 * Returns a list with the same term
	 */
	private List<SectionInformationObject> sortTerm(
			List<SectionInformationObject> course, String term) {

		if (course == null) {
			return null;
		}

		List<SectionInformationObject> day = new LinkedList<SectionInformationObject>();

		for (int i = 0; i < course.size(); i++) {
			SectionInformationObject section = course.get(i);

			if (section.getTerm().equals(term)) {
				day.add(section);
			}
		}

		return day;
	}

	/*
	 * 
	 */
	private List<SectionInformationObject> sortByDay(
			List<SectionInformationObject> course, String today) {

		if (course == null) {
			return null;
		}

		List<SectionInformationObject> day = new LinkedList<SectionInformationObject>();

		for (int i = 0; i < course.size(); i++) {
			SectionInformationObject section = course.get(i);

			String days = section.getDay();
			String[] daysing = days.split(" ");

			for (int j = 0; j < daysing.length; j++) {
				if (today.equals(daysing[j])) {
					day.add(section);
				}
			}

		}
		return day;
	}

	/*
	 * sorts for the same day.
	 */
	private String sortDayBreak(List<SectionInformationObject> course,
			String today) {

		if (course == null) {
			return null;
		}

		List<SectionInformationObject> day = new LinkedList<SectionInformationObject>();

		for (int i = 0; i < course.size(); i++) {
			SectionInformationObject section = course.get(i);

			String days = section.getDay();
			String[] daysing = days.split(" ");

			for (int j = 0; j < daysing.length; j++) {
				if (today.equals(daysing[j])) {
					day.add(section);
				}
			}

		}

		return findBreakinDay(day, today);
	}

	public String[] getStartEnd(List<SectionInformationObject> day) {
		String[] startEnd = new String[2];
		startEnd[0] = "8";
		startEnd[1] = "17";
		if (!day.isEmpty()) {
			SectionInformationObject start = findMin(day);
			if (start != null && start.getStart().contains(":"))
				startEnd[0] = start.getStart().split(":")[0];
			SectionInformationObject end = findMax(day);
			if (end != null && end.getEnd().contains(":"))
				startEnd[1] = end.getEnd().split(":")[0];
		}
		return startEnd;
	}
	
	public SectionInformationObject findMin(
			List<SectionInformationObject> courses) {
		SectionInformationObject min;

		if (courses == null || courses.size() == 0) {
			return null;
		} else if (courses.size() == 1) {
			return courses.get(0);
		} else {
			min = courses.get(0);
			for (int i = 1; i < courses.size(); i++) {

				// Parse the courses' time, only needs to check the first
				// because the start is always lesser than the end.
				String[] t_start = courses.get(i).getStart().split(":");
				int t_start_hour = Integer.parseInt(t_start[0]);
				int t_start_min = Integer.parseInt(t_start[1]);

				// Parse the min's time
				String[] m_start = min.getStart().split(":");
				int m_start_hour = Integer.parseInt(m_start[0]);
				int m_start_min = Integer.parseInt(m_start[1]);

				// Now compare the hours, if == then compare the min
				if (t_start_hour < m_start_hour) {
					min = courses.get(i);
				} else if (t_start_hour == m_start_hour) {
					// Check if the mins are the same
					if (t_start_min < m_start_min) {
						min = courses.get(i);
					}
				}

			}
		}
		return min;
	}

	// Exactly the same as the findMin but the sign are changed.
	// Instead of getting Start, we get End
	public SectionInformationObject findMax(
			List<SectionInformationObject> courses) {
		SectionInformationObject max;

		if (courses == null || courses.size() == 0) {
			return null;
		} else if (courses.size() == 1) {
			return courses.get(0);
		} else {
			max = courses.get(0);
			for (int i = 1; i < courses.size(); i++) {

				// Parse the courses' time, only needs to check the first
				// because the start is always lesser than the end.
				String[] t_start = courses.get(i).getEnd().split(":");
				int t_start_hour = Integer.parseInt(t_start[0]);
				int t_start_min = Integer.parseInt(t_start[1]);

				// Parse the min's time
				String[] m_start = max.getEnd().split(":");
				int m_start_hour = Integer.parseInt(m_start[0]);
				int m_start_min = Integer.parseInt(m_start[1]);

				// Now compare the hours, if == then compare the min
				if (t_start_hour > m_start_hour) {
					max = courses.get(i);
				} else if (t_start_hour == m_start_hour) {
					// Check if the mins are the same
					if (t_start_min > m_start_min) {
						max = courses.get(i);
					}
				}

			}
		}
		return max;
	}
}

